home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / tw14w12s.zoo / tw14w12s / textwin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-10  |  28.5 KB  |  1,270 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <stdlib.h>
  14.  
  15. #define CLEARED 2        /* redrawing a cleared area */
  16.  
  17. int default_height = 10;    /* default font height (points) */
  18. int default_font = 1;        /* default font (pixels) */
  19. int align_windows = 0;        /* align windows on byte boundaries */
  20.  
  21. /* if a font doesn't define a character, use this one instead */
  22. #define DEFAULT_CHAR '?'
  23.  
  24. static void set_cwidths __PROTO((TEXTWIN *));
  25.  
  26. /* functions for converting x, y pixels to/from character coordinates */
  27. /* NOTES: these functions give the upper left corner; to actually draw
  28.  * a character, they must be adjusted down by t->cbase
  29.  * Also: char2pixel accepts out of range character/column combinations,
  30.  * but pixel2char never will generate such combinations.
  31.  */
  32. void
  33. char2pixel(t, col, row, xp, yp)
  34.     TEXTWIN *t;
  35.     int col, row;
  36.     int *xp, *yp;
  37. {
  38.     short *WIDE = t->cwidths;
  39.     int x;
  40.  
  41.     *yp = t->win->wi_y - t->offy + row * t->cheight;
  42.     if (!WIDE) {
  43.         *xp = t->win->wi_x - t->offx + col * t->cmaxwidth;
  44.     } else if (col >= t->maxx) {
  45.         *xp = t->win->wi_x + t->win->wi_w;
  46.     } else {
  47.         x = t->win->wi_x - t->offx;
  48.         while(--col >= 0) {
  49.             x += WIDE[t->data[row][col]];
  50.         }
  51.         *xp = x;
  52.     }
  53. }
  54.  
  55. void
  56. pixel2char(t, x, y, colp, rowp)
  57.     TEXTWIN *t;
  58.     int x, y, *colp, *rowp;
  59. {
  60.     int col, row, count, nextcount;
  61.     short *WIDE = t->cwidths;
  62.  
  63.     row = (y - t->win->wi_y + t->offy) / t->cheight;
  64.     x = x - t->win->wi_x + t->offx;
  65.  
  66.     if (WIDE == 0) {
  67.         col = x / t->cmaxwidth;
  68.     } else {
  69.         count = 0;
  70.         for (col = 0; col < t->maxx - 1; col++) {
  71.             nextcount = count + WIDE[t->data[row][col]];
  72.             if (count <= x && x < nextcount) break;
  73.             count = nextcount;
  74.         }
  75.     }
  76.     *rowp = row;
  77.     *colp = col;
  78. }
  79.  
  80. static void set_scroll_bars __PROTO((TEXTWIN *));
  81.  
  82. /*
  83.  * draw a (part of a) line on screen, with certain attributes (e.g.
  84.  * inverse video) indicated by "flag". (x, y) is the upper left corner
  85.  * of the box which will contain the line.
  86.  * If "force" is 1, we may assume that the screen is already cleared
  87.  * (this is done in update_screen() for us).
  88.  * SPECIAL CASE: if buf is an empty string, we clear from "x" to
  89.  * the end of the window.
  90.  */
  91. static void
  92. draw_buf(t, buf, x, y, flag, force)
  93.     TEXTWIN *t;
  94.     char *buf;
  95.     int x, y, flag, force;
  96. {
  97.     char *s, *lastnonblank;
  98.     int x2, fillcolor, textcolor;
  99.     int texteffects;
  100.     short *WIDE = t->cwidths;
  101.     int temp[4];
  102.  
  103.     fillcolor = flag & CBGCOL;
  104.     textcolor = (flag & CFGCOL) >> 4;
  105.     texteffects = (flag & CEFFECTS) >> 8;
  106.  
  107. #ifdef STIPPLE_SELECT
  108.     if (flag & CINVERSE) {    /* swap foreground and background */
  109.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  110.     }
  111. #else
  112.     if (flag & (CINVERSE|CSELECTED)) {    /* swap foreground and background */
  113.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  114.     }
  115. #endif
  116.     x2 = x;
  117.     s = buf;
  118.     if (*s) {
  119.         lastnonblank = s-1;
  120.         while (*s) {
  121.             if (*s != ' ') lastnonblank = s;
  122.             if (WIDE)
  123.                 x2 += WIDE[*s];
  124.             else
  125.                 x2 += t->cmaxwidth;
  126.             s++;
  127.         }
  128.         lastnonblank++;
  129.         if (!(flag & CE_UNDERLINE))
  130.             *lastnonblank = 0;
  131.     } else {
  132.         x2 = t->win->wi_x + t->win->wi_w;
  133.     }
  134.  
  135.     set_wrmode(2);        /* transparent text */
  136.     if (fillcolor != 0 || (force != CLEARED)) {
  137.     /* the background may not be set correctly, so we do it here */
  138.         temp[0] = x;
  139.         temp[1] = y;
  140.         temp[2] = x2 - 1;
  141.         temp[3] = y + t->cheight - 1;
  142.         set_fillcolor(fillcolor);
  143.         set_fillstyle(1, 1);        /* fill the area completely */
  144.         v_bar(vdi_handle, temp);
  145.     }
  146.  
  147. /* skip leading blanks -- we don't need to draw them again! */
  148.     if (!(flag & CE_UNDERLINE)) {
  149.         while (*buf == ' ') {
  150.             buf++;
  151.             x += WIDE ? WIDE[' '] : t->cmaxwidth;
  152.         }
  153.     }
  154.  
  155.     if (*buf) {
  156.         set_textcolor(textcolor);
  157.         set_texteffects(texteffects);
  158.         v_gtext(vdi_handle, x, y + t->cbase, buf);
  159.     }
  160.  
  161. #ifdef STIPPLE_SELECT
  162.     if (flag & CSELECTED) {        /* put in the pattern */
  163.         set_wrmode(2);        /* 'OR' the pattern */
  164.         set_fillstyle(2, 2);
  165.         set_fillcolor(textcolor);
  166.         v_bar(vdi_handle, temp);
  167.     }
  168. #endif
  169. }
  170.  
  171. /*
  172.  * update the characters on screen between "firstline,firstcol" and 
  173.  * "lastline-1,lastcol-1" (inclusive)
  174.  * if force == 1, the redraw must occur, otherwise it occurs only for
  175.  * "dirty" characters. Note that we assume here that clipping
  176.  * rectanges and wind_update() have already been set for us.
  177.  */
  178.  
  179. static void
  180. update_chars(t, firstcol, lastcol, firstline, lastline, force)
  181.     TEXTWIN *t;
  182.     int firstcol, lastcol, firstline, lastline, force;
  183. {
  184. #define CBUFSIZ 127
  185.     UCHAR buf[CBUFSIZ+1], c;
  186.     int px, py, ax, i, cnt, flag, bufwidth;
  187.     short *WIDE = t->cwidths;
  188.     int lineforce = 0;
  189.     int curflag;
  190.  
  191. #define flushbuf()    \
  192.     {    buf[i] = 0;    \
  193.          draw_buf(t, buf, px, py, flag, lineforce); \
  194.          px += bufwidth; \
  195.          i = bufwidth = 0; \
  196.     }
  197.  
  198. /* make sure the font is set correctly */
  199.     set_font(t->cfont, t->cpoints);
  200.  
  201. /* find the place to start writing */
  202.     char2pixel(t, firstcol, firstline, &ax, &py);
  203.  
  204. /* now write the characters we need to */
  205.     while (firstline < lastline) {
  206. /* if no characters on the line need re-writing, skip the loop */
  207.         if (!force && t->dirty[firstline] == 0) {
  208.             py += t->cheight;
  209.             firstline++;
  210.             continue;
  211.         }
  212.         px = ax;
  213. /*
  214.  * now, go along collecting characters to write into the buffer
  215.  * we add a character to the buffer if and only if (1) the
  216.  * character's attributes (inverse video, etc.) match the
  217.  * attributes of the character already in the buffer, and
  218.  * (2) the character needs redrawing. Otherwise, if there are
  219.  * characters in the buffer, we flush the buffer.
  220.  */
  221.         i = bufwidth = 0;
  222.         cnt = firstcol;
  223.         flag = 0;
  224.         lineforce = force;
  225.         if (!lineforce && (t->dirty[firstline] & ALLDIRTY))
  226.             lineforce = 1;
  227.         while (cnt < lastcol) {
  228.             c = t->data[firstline][cnt];
  229.             if (lineforce ||
  230.                (t->cflag[firstline][cnt] & (CDIRTY|CTOUCHED))) {
  231. /* yes, this character needs drawing */
  232. /* if the font is proportional and the character has really changed,
  233.  * then all remaining characters will have to be redrawn, too
  234.  */
  235.             if (WIDE && (lineforce == 0) &&
  236.                 (t->cflag[firstline][cnt] & CDIRTY))
  237.                 lineforce = 1;
  238. /* watch out for characters that can't be drawn in this font */
  239.             if (c < t->minADE || c > t->maxADE)
  240.                 c = DEFAULT_CHAR;
  241.             curflag = t->cflag[firstline][cnt] & ~(CDIRTY|CTOUCHED);
  242.             if (flag == curflag) {
  243.                 buf[i++] = c;
  244.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  245.                 if (i == CBUFSIZ) {
  246.                 flushbuf();
  247.                 }
  248.             } else {
  249.                 if (i) {
  250.                 flushbuf();
  251.                 }
  252.                 flag = curflag;
  253.                 buf[i++] = c;
  254.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  255.             }
  256.             } else {
  257.             if (i) {
  258.                 flushbuf();
  259.             }
  260.             px += (WIDE ? WIDE[c] : t->cmaxwidth);
  261.             }
  262.             cnt++;
  263.         }
  264.         if (i) {
  265.             flushbuf();
  266.         }
  267.         if (WIDE) {        /* the line's 'tail' */
  268.             draw_buf(t, "", px, py, t->cflag[firstline][t->maxx-1],
  269.                 lineforce);
  270.         }
  271.         py += t->cheight;
  272.         firstline++;
  273.     }
  274. }
  275.  
  276. /*
  277.  * mark_clean: mark a window as having been completely updated
  278.  */
  279.  
  280. void
  281. mark_clean(t)
  282.     TEXTWIN *t;
  283. {
  284.     int line, col;
  285.  
  286.     for (line = 0; line < t->maxy; line++) {
  287.         if (t->dirty[line] == 0)
  288.             continue;
  289.         for (col = 0; col < t->maxx; col++) {
  290.             t->cflag[line][col] &= ~(CDIRTY|CTOUCHED);
  291.         }
  292.         t->dirty[line] = 0;
  293.     }
  294. }
  295.  
  296. /*
  297.  * redraw all parts of window v which are contained within the
  298.  * given rectangle. Assumes that the clipping rectange has already
  299.  * been set correctly.
  300.  * NOTE: more than one rectangle may cover the same area, so we
  301.  * can't mark the window clean during the update; we have to do
  302.  * it in a separate routine (mark_clean)
  303.  */
  304.  
  305. static MFDB scr_mfdb;    /* left NULL so it refers to the screen by default */
  306.  
  307. static void
  308. update_screen(t, xc, yc, wc, hc, force)
  309.     TEXTWIN *t;
  310.     int xc, yc, wc, hc;
  311.     int force;
  312. {
  313.     int firstline, lastline, firstscroll;
  314.     int firstcol, lastcol;
  315.     int pxy[8];
  316.     int scrollht = 0;
  317.  
  318. /* if t->scrolled is set, then the output routines faked the "dirty"
  319.  * flags on the scrolled lines under the assumption that we would
  320.  * do a blit scroll; so we do it here.
  321.  */
  322.     if ((force == 0) && t->scrolled &&
  323.         (scrollht = t->scrolled * t->cheight) < hc) {
  324.         pxy[0] = xc;
  325.         pxy[1] = yc + scrollht;
  326.         pxy[2] = xc + wc - 1;
  327.         pxy[3] = yc + hc - 1;
  328.         pxy[4] = xc;
  329.         pxy[5] = yc;
  330.         pxy[6] = pxy[2];
  331. #if 0
  332.         pxy[7] = pxy[1]-1;
  333. #else
  334.         pxy[7] = pxy[3] - scrollht;
  335. #endif
  336. #define FM_COPY 3
  337. #define FM_CLEAR 0
  338.         vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  339.     }
  340.  
  341. /* if `force' is set, clear the area to be redrawn -- it looks better */
  342.     if (force == CLEARED) {
  343. #ifdef WWA_TRUECOLOUR
  344. /* In truecolour, filling raster with 0's is not equivalent to filling
  345.  * it with colour 0 (unless colour 0 is black - but usually it's white!).
  346.  */
  347.         set_fillcolor(0);
  348.         set_fillstyle(1, 1);
  349.         pxy[0] = xc;
  350.         pxy[1] = yc;
  351.         pxy[2] = xc + wc - 1;
  352.         pxy[3] = yc + hc - 1;
  353.         vr_recfl(vdi_handle, pxy);
  354. #else
  355.         pxy[4] = pxy[0] = xc;
  356.         pxy[5] = pxy[1] = yc;
  357.         pxy[6] = pxy[2] = xc + wc - 1;
  358.         pxy[7] = pxy[3] = yc + hc - 1;
  359.         vro_cpyfm(vdi_handle, FM_CLEAR, pxy, &scr_mfdb, &scr_mfdb);
  360. #endif
  361.     }
  362.  
  363. /* convert from on-screen coordinates to window rows & columns */
  364.     pixel2char(t, xc, yc, &firstcol, &firstline);
  365.  
  366.     if (firstline < 0) firstline = 0;
  367.     else if (firstline >= t->maxy) firstline = t->maxy - 1;
  368.  
  369.     lastline = 1 + firstline + (hc + t->cheight - 1) / t->cheight;
  370.     if (lastline > t->maxy) lastline = t->maxy;
  371.  
  372. /* kludge for proportional fonts */
  373.     if (t->cwidths) {
  374.         firstcol = 0;
  375.         lastcol = t->maxx;
  376.     } else {
  377.         pixel2char(t, xc+wc+t->cmaxwidth-1, yc, &lastcol, &firstline);
  378.     }
  379.  
  380. /* if t->scrolled is set, the last few lines *must* be updated */
  381.     if (t->scrolled && force == 0) {
  382.         firstscroll = firstline + (hc - scrollht)/t->cheight;
  383.         if (firstscroll <= firstline) {
  384.             force = TRUE;
  385.         } else {
  386.             update_chars(t, firstcol, lastcol, firstscroll, lastline, TRUE);
  387.             lastline = firstscroll;
  388.         }
  389.     }
  390.     update_chars(t, firstcol, lastcol, firstline, lastline, force);
  391. }
  392.  
  393. /*
  394.  * redraw all parts of a window that need redrawing; this is called
  395.  * after, for example, writing some text into the window
  396.  */
  397.  
  398. void
  399. refresh_textwin(t)
  400.     TEXTWIN *t;
  401. {
  402.     WINDOW *v = t->win;
  403.     GRECT    t1, t2;
  404.  
  405.     if (v->wi_handle < 0) return;    /* window not visible */
  406.     wind_update(TRUE);
  407.     hide_mouse();
  408.     t2.g_x = t->win->wi_x;
  409.     t2.g_y = t->win->wi_y;
  410.     t2.g_w = t->win->wi_w;
  411.     t2.g_h = t->win->wi_h;
  412.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  413.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  414.  
  415.     while (t1.g_w && t1.g_h) {
  416.         if (rc_intersect(&t2, &t1)) {
  417.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  418.             update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, FALSE);
  419.           }
  420.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  421.              &t1.g_w, &t1.g_h);
  422.     }
  423.     t->scrolled = t->nbytes = t->draw_time = 0;
  424.     show_mouse();
  425.     mark_clean(t);
  426.     wind_update(FALSE);
  427. }
  428.  
  429. /*
  430.  * Methods for reacting to user events
  431.  */
  432.  
  433.  
  434. /* draw part of a window */
  435.  
  436. static void
  437. draw_textwin(v, x, y, w, h)
  438.     WINDOW *v;
  439.     int x, y, w, h;
  440. {
  441.     TEXTWIN *t = v->extra;
  442.  
  443.     t->scrolled = 0;
  444.     update_screen(v->extra, x, y, w, h, CLEARED);
  445.     t->nbytes = t->draw_time = 0;
  446. }
  447.  
  448. /* close a window (called when the closed box is clicked on) */
  449.  
  450. static void
  451. close_textwin(v)
  452.     WINDOW *v;
  453. {
  454.     void destroy_textwin();
  455.  
  456.     destroy_textwin(v->extra);
  457. }
  458.  
  459. /* resize a window to its "full" size */
  460.  
  461. static void
  462. full_textwin(v)
  463.     WINDOW *v;
  464. {
  465.     int newx, newy, neww, newh;
  466.  
  467.     if (v->flags & WFULLED) {
  468.         wind_get(v->wi_handle, WF_PREVXYWH, &newx, &newy, &neww,
  469.              &newh);
  470.     } else {
  471.         wind_get(v->wi_handle, WF_FULLXYWH, &newx, &newy, &neww,
  472.             &newh);
  473.     }
  474.  
  475.     wind_calc(WC_WORK, v->wi_kind, newx, newy, neww, newh,
  476.           &v->wi_x, &v->wi_y, &v->wi_w, &v->wi_h);
  477.     if (align_windows && (v->wi_x & 7)) {
  478.         v->wi_x &= ~7;
  479.         wind_calc(WC_BORDER, v->wi_kind, v->wi_x, v->wi_y, v->wi_w,
  480.             v->wi_h, &newx, &newy, &neww, &newh);
  481.     }
  482.     wind_set(v->wi_handle, WF_CURRXYWH, newx, newy, neww, newh);
  483.     v->flags ^= WFULLED;
  484.     set_scroll_bars(v->extra);
  485. }
  486.  
  487. /* resize a window */
  488.  
  489. static void redo __PROTO(( TEXTWIN * ));
  490.  
  491. static void
  492. move_textwin(v, x, y, w, h)
  493.     WINDOW *v;
  494.     int x, y, w, h;
  495. {
  496.     int fullx, fully, fullw, fullh;
  497.  
  498.     wind_get(v->wi_handle, WF_FULLXYWH, &fullx, &fully, &fullw, &fullh);
  499.  
  500.     if (w > fullw) w = fullw;
  501.     if (h > fullh) h = fullh;
  502.     wind_calc(WC_WORK, v->wi_kind, x, y, w, h, &v->wi_x,
  503.         &v->wi_y, &v->wi_w, &v->wi_h);
  504.     if (align_windows) {
  505.         v->wi_x &= ~7;
  506.         wind_calc(WC_BORDER, v->wi_kind, v->wi_x, v->wi_y, v->wi_w, v->wi_h,
  507.             &x, &y, &w, &h);
  508.     }
  509.     wind_set(v->wi_handle, WF_CURRXYWH, x, y, w, h);
  510.     if (w != fullw || h != fullh)
  511.         v->flags &= ~WFULLED;
  512. }
  513.  
  514. static void
  515. size_textwin(v, x, y, w, h)
  516.     WINDOW *v;
  517.     int x, y, w, h;
  518. {
  519.     TEXTWIN *t = v->extra;
  520.  
  521.     (*v->moved)(v, x, y, w, h);
  522.     set_scroll_bars(t);
  523. }
  524.  
  525. /*
  526.  * handle an arrow event to a window
  527.  */
  528.  
  529. static void
  530. newxoff(t, x)
  531.     TEXTWIN *t;
  532.     int x;
  533. {
  534.     t->offx = x;
  535.     set_scroll_bars(t);
  536. }
  537.  
  538. static void
  539. newyoff(t, y)
  540.     TEXTWIN *t;
  541.     int y;
  542. {
  543.     t->offy = y;
  544.     set_scroll_bars(t);
  545. }
  546.  
  547. /*
  548.  * redisplay a text window in its entirety, but without pre-clearing
  549.  * areas: this looks better when arrowing and paging
  550.  */
  551.  
  552. static void
  553. redo(t)
  554.     TEXTWIN *t;
  555. {
  556.     WINDOW *v;
  557.     int xc, yc, wc, hc;
  558.     GRECT    t1, t2;
  559.  
  560.     v = t->win;
  561.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  562.  
  563.     wind_update(TRUE);
  564.     hide_mouse();
  565.     t2.g_x = xc;
  566.     t2.g_y = yc;
  567.     t2.g_w = wc;
  568.     t2.g_h = hc;
  569.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  570.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  571.  
  572.     while (t1.g_w && t1.g_h) {
  573.         if (rc_intersect(&t2, &t1)) {
  574.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  575.             update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  576.           }
  577.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  578.              &t1.g_w, &t1.g_h);
  579.     }
  580.     t->scrolled = t->nbytes = t->draw_time = 0;
  581.     show_mouse();
  582.     mark_clean(t);
  583.     wind_update(FALSE);
  584. }
  585.  
  586. #define UP 0
  587. #define DOWN 1
  588.  
  589. #define scrollup(t, off) scrollupdn(t, off, UP)
  590. #define scrolldn(t, off) scrollupdn(t, off, DOWN)
  591.  
  592. static void
  593. scrollupdn(t, off, direction)
  594.     TEXTWIN *t;
  595.     int off;
  596.     int direction;
  597. {
  598.     WINDOW *v;
  599.     int xc, yc, wc, hc;
  600.     GRECT    t1, t2;
  601.     int pxy[8];
  602.  
  603.     v = t->win;
  604.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  605.  
  606.     if (off <= 0) {
  607.         return;
  608.     }
  609.  
  610.     wind_update(TRUE);
  611.     hide_mouse();
  612.     t2.g_x = xc;
  613.     t2.g_y = yc;
  614.     t2.g_w = wc;
  615.     t2.g_h = hc;
  616.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  617.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  618.  
  619.     while (t1.g_w && t1.g_h) {
  620.         if (rc_intersect(&t2, &t1)) {
  621.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  622.             if (off >= t1.g_h) {
  623.                 update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  624.             } else {
  625.                 if (direction  == UP) {
  626.                     pxy[0] = t1.g_x;    /* "from" address */
  627.                     pxy[1] = t1.g_y + off;
  628.                     pxy[2] = t1.g_x + t1.g_w - 1;
  629.                     pxy[3] = t1.g_y + t1.g_h - 1;
  630.                     pxy[4] = t1.g_x;    /* "to" address */
  631.                     pxy[5] = t1.g_y;
  632.                     pxy[6] = t1.g_x + t1.g_w - 1;
  633.                     pxy[7] = t1.g_y + t1.g_h - off - 1;
  634.                 } else {
  635.                     pxy[0] = t1.g_x;
  636.                     pxy[1] = t1.g_y;
  637.                     pxy[2] = t1.g_x + t1.g_w - 1;
  638.                     pxy[3] = t1.g_y + t1.g_h - off - 1;
  639.                     pxy[4] = t1.g_x;
  640.                     pxy[5] = t1.g_y + off;
  641.                     pxy[6] = t1.g_x + t1.g_w - 1;
  642.                     pxy[7] = t1.g_y + t1.g_h - 1;
  643.                 }
  644.                 vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  645.                 if (direction == UP)
  646.                     update_screen(t, t1.g_x, pxy[7], t1.g_w, off, TRUE);
  647.                 else
  648.                     update_screen(t, t1.g_x, t1.g_y, t1.g_w, off, TRUE);
  649.             }
  650.           }
  651.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  652.              &t1.g_w, &t1.g_h);
  653.     }
  654.     show_mouse();
  655.     wind_update(FALSE);
  656. }
  657.  
  658. #define LEFT 0
  659. #define RIGHT 1
  660.  
  661. #define scrolllf(t, off) scrollleftright(t, off, LEFT)
  662. #define scrollrt(t, off) scrollleftright(t, off, RIGHT)
  663.  
  664. static void
  665. scrollleftright(t, off, direction)
  666.     TEXTWIN *t;
  667.     int off;
  668.     int direction;
  669. {
  670.     WINDOW *v;
  671.     int xc, yc, wc, hc;
  672.     GRECT    t1, t2;
  673.     int pxy[8];
  674.  
  675.     v = t->win;
  676.     xc = v->wi_x; yc = v->wi_y; wc = v->wi_w; hc = v->wi_h;
  677.  
  678.     if (off <= 0) {
  679.         return;
  680.     }
  681.  
  682.     wind_update(TRUE);
  683.     hide_mouse();
  684.     t2.g_x = xc;
  685.     t2.g_y = yc;
  686.     t2.g_w = wc;
  687.     t2.g_h = hc;
  688.     wind_get(v->wi_handle, WF_FIRSTXYWH,
  689.          &t1.g_x, &t1.g_y, &t1.g_w, &t1.g_h);
  690.  
  691.     while (t1.g_w && t1.g_h) {
  692.         if (rc_intersect(&t2, &t1)) {
  693.             set_clip(t1.g_x, t1.g_y, t1.g_w, t1.g_h);
  694.             if (off >= t1.g_w) {
  695.                 update_screen(t, t1.g_x, t1.g_y, t1.g_w, t1.g_h, TRUE);
  696.             } else {
  697.                 if (direction == LEFT) {
  698.                     pxy[0] = t1.g_x + off;    /* "from" address */
  699.                     pxy[1] = t1.g_y;
  700.                     pxy[2] = t1.g_x + t1.g_w - 1;
  701.                     pxy[3] = t1.g_y + t1.g_h - 1;
  702.                     pxy[4] = t1.g_x;    /* "to" address */
  703.                     pxy[5] = t1.g_y;
  704.                     pxy[6] = t1.g_x + t1.g_w - off - 1;
  705.                     pxy[7] = t1.g_y + t1.g_h - 1;
  706.                 } else {
  707.                     pxy[0] = t1.g_x;
  708.                     pxy[1] = t1.g_y;
  709.                     pxy[2] = t1.g_x + t1.g_w - off - 1;
  710.                     pxy[3] = t1.g_y + t1.g_h;
  711.                     pxy[4] = t1.g_x + off;
  712.                     pxy[5] = t1.g_y;
  713.                     pxy[6] = t1.g_x + t1.g_w - 1;
  714.                     pxy[7] = t1.g_y + t1.g_h - 1;
  715.                 }
  716.                 vro_cpyfm(vdi_handle, FM_COPY, pxy, &scr_mfdb, &scr_mfdb);
  717.                 if (direction == LEFT)
  718.                     update_screen(t, pxy[6], t1.g_y, off, t1.g_h, TRUE);
  719.                 else
  720.                     update_screen(t, t1.g_x, t1.g_y, off, t1.g_h, TRUE);
  721.             }
  722.           }
  723.         wind_get(v->wi_handle, WF_NEXTXYWH, &t1.g_x, &t1.g_y,
  724.              &t1.g_w, &t1.g_h);
  725.     }
  726.     show_mouse();
  727.     wind_update(FALSE);
  728. }
  729.  
  730. static void
  731. arrow_textwin(v, msg)
  732.     WINDOW *v;
  733.     int msg;
  734. {
  735.     TEXTWIN *t = (TEXTWIN *)v->extra;
  736.     int oldoff;
  737.  
  738.     refresh_textwin(t);
  739.  
  740.     switch(msg) {
  741.     case WA_UPPAGE:
  742.         newyoff(t, t->offy - v->wi_h);
  743.         break;
  744.     case WA_DNPAGE:
  745.         newyoff(t, t->offy + v->wi_h);
  746.         break;
  747.     case WA_UPLINE:
  748.         oldoff = t->offy;
  749.         newyoff(t, t->offy - t->cheight);
  750.         scrolldn(t, oldoff - t->offy);
  751.         return;
  752.     case WA_DNLINE:
  753.         oldoff = t->offy;
  754.         newyoff(t, t->offy + t->cheight);
  755.         scrollup(t, t->offy - oldoff);
  756.         return;
  757.     case WA_LFPAGE:
  758.         newxoff(t, t->offx - v->wi_w);
  759.         break;
  760.     case WA_RTPAGE:
  761.         newxoff(t, t->offx + v->wi_w);
  762.         break;
  763.     case WA_LFLINE:
  764.         oldoff = t->offx;
  765.         newxoff(t, t->offx - t->cmaxwidth);
  766.         scrollrt(t, oldoff - t->offx);
  767.         return;
  768.     case WA_RTLINE:
  769.         oldoff = t->offx;
  770.         newxoff(t, t->offx + t->cmaxwidth);
  771.         scrolllf(t, t->offx - oldoff);
  772.         return;
  773.     }
  774.     redo(t);
  775. }
  776.  
  777. /*
  778.  * handle horizontal and vertical slider events for a window
  779.  */
  780.  
  781. static void
  782. hslid_textwin(v, hpos)
  783.     WINDOW *v;
  784.     int hpos;
  785. {
  786.     TEXTWIN *t = (TEXTWIN *)v->extra;
  787.     long width;
  788.     int oldoff;
  789.  
  790.     width = t->cmaxwidth * t->maxx - v->wi_w;
  791.     oldoff = t->offx;
  792.     newxoff(t, (int)( (hpos * width) / 1000 ));
  793.     oldoff -= t->offx;
  794.     if (oldoff < 0)
  795.         scrolllf(t, -oldoff);
  796.     else
  797.         scrollrt(t, oldoff);
  798. }
  799.  
  800. static void
  801. vslid_textwin(v, vpos)
  802.     WINDOW *v;
  803.     int vpos;
  804. {
  805.     TEXTWIN *t = (TEXTWIN *)v->extra;
  806.     long height;
  807.     int oldoff;
  808.  
  809.     height = t->cheight * t->maxy - v->wi_h;
  810.     oldoff = t->offy;
  811.     newyoff(t, (int)( (vpos * height) / 1000));
  812.     oldoff -= t->offy;
  813.     if (oldoff < 0)
  814.         scrollup(t, -oldoff);
  815.     else
  816.         scrolldn(t, oldoff);
  817. }
  818.  
  819. /*
  820.  * correctly set up the horizontal and vertical scroll bars for TEXTWIN
  821.  * t
  822.  */
  823.  
  824. static void
  825. set_scroll_bars(t)
  826.     TEXTWIN *t;
  827. {
  828.     WINDOW *v = t->win;
  829.     int hsize, vsize;
  830.     int hpos, vpos;
  831.     long width, height;
  832.  
  833.     width = t->cmaxwidth * t->maxx;
  834.     height = t->cheight * t->maxy;
  835.  
  836. /* see if the new offset is too big for the window */
  837.     if (t->offx + v->wi_w > width) {
  838.         t->offx  = width - v->wi_w;
  839.     }
  840.     if (t->offx < 0) t->offx = 0;
  841.  
  842.     if (t->offy + v->wi_h > height) {
  843.         t->offy = height - v->wi_h;
  844.     }
  845.     if (t->offy < 0) t->offy = 0;
  846.  
  847.     hsize = 1000L * v->wi_w / width;
  848.     if (hsize > 1000) hsize = 1000;
  849.     else if (hsize < 1) hsize = 1;
  850.  
  851.     vsize = 1000L * v->wi_h / height;
  852.     if (vsize > 1000) vsize = 1000;
  853.     else if (vsize < 1) vsize = 1;
  854.  
  855.     if (width > v->wi_w)
  856.         hpos = 1000L * t->offx / (width - v->wi_w);
  857.     else
  858.         hpos = 1;
  859.  
  860.     if (height > v->wi_h)
  861.         vpos = 1000L * t->offy / (height - v->wi_h);
  862.     else
  863.         vpos = 1;
  864.  
  865.     if (hpos < 1) hpos = 1;
  866.     else if (hpos > 1000) hpos = 1000;
  867.  
  868.     if (vpos < 1) vpos = 1;
  869.     else if (vpos > 1000) vpos = 1000;
  870.  
  871.     if (v->wi_kind & HSLIDE) {
  872.         wind_set(v->wi_handle, WF_HSLIDE, hpos, 0, 0, 0);
  873.         wind_set(v->wi_handle, WF_HSLSIZE, hsize, 0, 0, 0);
  874.     }
  875.     if (v->wi_kind & VSLIDE) {
  876.         wind_set(v->wi_handle, WF_VSLIDE, vpos, 0, 0, 0);
  877.         wind_set(v->wi_handle, WF_VSLSIZE, vsize, 0, 0, 0);
  878.     }
  879. }
  880.  
  881. static void
  882. output_textwin(t, c)
  883.     TEXTWIN *t;
  884.     int c;
  885. {
  886.     c &= 0x00ff;
  887.     if (!c) return;
  888.  
  889.     if (c == '\r') {
  890.         t->cx = 0; return;
  891.     }
  892.     if (c == '\n') {
  893.         t->cx = 0;
  894.         if (t->cy < t->maxy - 1)
  895.             t->cy++;
  896.         return;
  897.     }
  898.     t->data[t->cy][t->cx] = c;
  899.     t->cflag[t->cy][t->cx] = CDIRTY | ((c>='A' && c<='Z') ? CINVERSE : 0)
  900.                     | COLORS(1, 0);
  901.  
  902.     t->dirty[t->cy] |= SOMEDIRTY;
  903.     t->cx++;
  904.     if (t->cx >= t->maxx) {
  905.         if (t->term_flags & FWRAP) {
  906.             t->cx = 0;
  907.             t->cy++;
  908.             if (t->cy >= t->maxy)
  909.                 t->cy = t->maxy - 1;
  910.         } else {
  911.             t->cx = t->maxx - 1;
  912.         }
  913.     }
  914.     refresh_textwin(t);
  915. }
  916.  
  917. /*
  918.  * Create a new text window with title t, w columns, and h rows,
  919.  * and place it at x, y on the screen; the new window should have the
  920.  * set of gadgets specified by "kind", and should provide "s"
  921.  * lines of scrollback.
  922.  */
  923.  
  924. TEXTWIN *
  925. create_textwin(title, x, y, w, h, s, kind)
  926.     char *title;
  927.     int x, y, w, h, s, kind;
  928. {
  929.     WINDOW *v;
  930.     TEXTWIN *t;
  931.     int firstchar, lastchar, distances[5], maxwidth, effects[3];
  932.     int width, height;
  933.     extern int default_height;    /* in main.c */
  934.     int i, j;
  935.  
  936.     extern void normal_putch();
  937.  
  938.     t = malloc(sizeof(TEXTWIN));
  939.     if (!t) return t;
  940.  
  941.     t->maxx = w;
  942.     t->maxy = h+s;
  943.     t->miny = s;
  944.     t->cx = 0;
  945.     t->cy = t->miny;
  946.  
  947. /* we get font data from the VDI */
  948.     set_font(default_font, default_height);
  949.     vqt_fontinfo(vdi_handle, &firstchar, &lastchar, distances, &maxwidth,
  950.              effects);
  951.     t->cfont = default_font;
  952.     t->cpoints = default_height;
  953.     t->cmaxwidth = maxwidth;
  954.     t->cheight = distances[0]+distances[4]+1;
  955.     t->cbase = distances[4];
  956.     t->minADE = firstchar;
  957.     t->maxADE = lastchar;
  958.     t->cwidths = 0;
  959.     set_cwidths(t);
  960.  
  961. /* initialize the window data */
  962.     t->data = malloc(sizeof(char *) * t->maxy);
  963.     t->cflag = malloc(sizeof(short *) * t->maxy);
  964.     t->dirty = malloc((size_t)t->maxy);
  965.  
  966.     if (!t->dirty || !t->cflag || !t->data) return 0;
  967.  
  968.     for (i = 0; i < t->maxy; i++) {
  969.         t->dirty[i] = 0; /* the window starts off clear */
  970.         t->data[i] = malloc((size_t)t->maxx+1);
  971.         t->cflag[i] = malloc(sizeof(short) * (size_t)(t->maxx+1));
  972.         if (!t->cflag[i] || !t->data[i]) return 0;
  973.         for (j = 0; j < t->maxx; j++) {
  974.             t->data[i][j] = ' ';
  975.             t->cflag[i][j] = COLORS(1, 0);
  976.         }
  977.     }
  978.  
  979.     t->scrolled = t->nbytes = t->draw_time = 0;
  980.  
  981. /* calculate max. window size, and initialize the WINDOW struct */
  982.     width = t->maxx * t->cmaxwidth;
  983.     height = h * t->cheight;
  984.     v = create_window(title, kind, x, y, width, height);
  985.     if (!v) {
  986.         free(t);
  987.         return 0;
  988.     }
  989.  
  990.     v->extra = t;
  991.     v->wtype = TEXT_WIN;
  992.     t->win = v;
  993.  
  994. /* initialize all the methods for v */
  995.     v->draw = draw_textwin;
  996.     v->closed = close_textwin;
  997.     v->fulled = full_textwin;
  998.     v->moved = move_textwin;
  999.     v->sized = size_textwin;
  1000.     v->arrowed = arrow_textwin;
  1001.     v->hslid = hslid_textwin;
  1002.     v->vslid = vslid_textwin;
  1003.  
  1004.     t->offx = 0;
  1005.     t->offy = s * t->cheight;
  1006.  
  1007.     t->output = output_textwin;
  1008.     t->term_cattr = COLORS(1, 0);
  1009.     t->term_flags = FWRAP;
  1010.     t->fd = t->pgrp = 0;
  1011.  
  1012.     t->prog = t->cmdlin = t->progdir = 0;
  1013.     t->flashtimer = t->flashperiod = 0;
  1014.     return t;
  1015. }
  1016.  
  1017. /*
  1018.  * destroy a text window
  1019.  */
  1020.  
  1021. #include <osbind.h>
  1022. #include <mintbind.h>
  1023. #include <signal.h>
  1024.  
  1025. void
  1026. destroy_textwin(t)
  1027.     TEXTWIN *t;
  1028. {
  1029.     int i;
  1030.  
  1031.     destroy_window(t->win);
  1032.     for (i = 0; i < t->maxy; i++) {
  1033.         free(t->data[i]);
  1034.         free(t->cflag[i]);
  1035.     }
  1036.     if (t->prog) free(t->prog);
  1037.     if (t->cmdlin) free(t->cmdlin);
  1038.     if (t->progdir) free(t->progdir);
  1039.  
  1040.     free(t->cflag);
  1041.     free(t->data);
  1042.     free(t->dirty);
  1043.     if (t->cwidths) free(t->cwidths);
  1044.     free(t);
  1045.  
  1046.     if (t->fd > 0)
  1047.         (void)Fclose(t->fd);
  1048.     if (t->pgrp > 0)
  1049.         (void)Pkill(-t->pgrp, SIGHUP);
  1050. }
  1051.  
  1052. /*
  1053.  * reset a window's font: this involves resizing the window, too
  1054.  */
  1055.  
  1056. void
  1057. textwin_setfont(t, font, points)
  1058.     TEXTWIN *t;
  1059.     int font;
  1060.     int points;
  1061. {
  1062.     extern int win_flourishes;    /* in window.c */
  1063.     WINDOW *w;
  1064.     int firstchar, lastchar, distances[5], maxwidth, effects[3];
  1065.     int width, height;
  1066.     int dummy;
  1067.     int oldflourishes = win_flourishes;
  1068.     int reopen = 0;
  1069.  
  1070.     w = t->win;
  1071.  
  1072.     if (t->cfont == font && t->cpoints == points)
  1073.         return;        /* no real change happens */
  1074.  
  1075.     win_flourishes = 0;    /* no silly effects, thank you */
  1076.     if (w->wi_handle >= 0) {
  1077.         wind_close(w->wi_handle);
  1078.         wind_delete(w->wi_handle);
  1079.         reopen = 1;
  1080.     }
  1081.     w->wi_handle = -1;
  1082.  
  1083.     t->cfont = font;
  1084.     t->cpoints = points;
  1085.     set_font(font, points);
  1086.     vqt_fontinfo(vdi_handle, &firstchar, &lastchar, distances, &maxwidth,
  1087.              effects);
  1088.     t->cmaxwidth = maxwidth;
  1089.     t->cheight = distances[0]+distances[4]+1;
  1090.     t->cbase = distances[4];
  1091.     t->minADE = firstchar;
  1092.     t->maxADE = lastchar;
  1093.     set_cwidths(t);
  1094.  
  1095.     width = NCOLS(t) * t->cmaxwidth;
  1096.     height = NROWS(t) * t->cheight;
  1097.  
  1098.     wind_calc(WC_BORDER, w->wi_kind, w->wi_fullx, w->wi_fully, width,
  1099.         height, &dummy, &dummy, &w->wi_fullw, &w->wi_fullh);
  1100.     if (w->wi_fullw > wdesk) w->wi_fullw = wdesk;
  1101.     if (w->wi_fullh > hdesk) w->wi_fullh = hdesk;
  1102.  
  1103.     if (w->wi_fullx + w->wi_fullw > xdesk + wdesk)
  1104.         w->wi_fullx = xdesk + (wdesk - w->wi_fullw)/2;
  1105.     if (w->wi_fully + w->wi_fullh > ydesk + hdesk)
  1106.         w->wi_fully = ydesk + (hdesk - w->wi_fullh)/2;
  1107.  
  1108.     wind_calc(WC_WORK, w->wi_kind, w->wi_fullx, w->wi_fully, w->wi_fullw, w->wi_fullh,
  1109.         &dummy, &dummy, &width, &height);
  1110.  
  1111.     if (w->wi_w > width) w->wi_w = width;
  1112.     if (w->wi_h > height) w->wi_h = height;
  1113.  
  1114.     if (reopen)
  1115.         open_window(w);
  1116.     win_flourishes = oldflourishes;
  1117. }
  1118.  
  1119. /*
  1120.  * make a text window have a new number of rows and columns, and
  1121.  * a new amount of scrollback
  1122.  */
  1123.  
  1124. void
  1125. resize_textwin(t, cols, rows, scrollback)
  1126.     TEXTWIN *t;
  1127.     int cols, rows, scrollback;
  1128. {
  1129.     extern int win_flourishes;    /* in window.c */
  1130.     WINDOW *w = t->win;
  1131.     int i, j, mincols;
  1132.     int delta;
  1133.     UCHAR **newdata;
  1134.     short **newcflag;
  1135.     char *newdirty;
  1136.     int width, height, dummy;
  1137.     int oldflourishes = win_flourishes;
  1138.     int reopen = 0;
  1139.  
  1140.     if (t->maxx == cols && t->miny == scrollback &&
  1141.         t->maxy == rows+scrollback)
  1142.         return;        /* no change */
  1143.     newdata = malloc(sizeof(char *) * (rows+scrollback));
  1144.     newcflag = malloc(sizeof(short *) * (rows+scrollback));
  1145.     newdirty = malloc((size_t)(rows+scrollback));
  1146.     if (!newdata || !newcflag || !newdirty)
  1147.         return;
  1148.  
  1149.     mincols = (cols < t->maxx) ? cols : t->maxx;
  1150.  
  1151. /* first, initialize the new data to blanks */
  1152.     for (i = 0; i < rows+scrollback; i++) {
  1153.         newdirty[i] = 0;
  1154.         newdata[i] = malloc((size_t)cols+1);
  1155.         newcflag[i] = malloc(sizeof(short)*(cols+1));
  1156.         if (!newcflag[i] || !newdata[i])
  1157.             return;
  1158.         for(j = 0; j < cols; j++) {
  1159.             newdata[i][j] = ' '; newcflag[i][j] = COLORS(1, 0);
  1160.         }
  1161.     }
  1162.  
  1163. /* now, copy as much scrollback as we can */
  1164.  
  1165.     if (rows+scrollback >= t->maxy) {
  1166.         delta = rows+scrollback - t->maxy;
  1167.         for (i = 0; i < t->maxy;i++) {
  1168.             for (j = 0; j < mincols; j++) {
  1169.                 newdata[i+delta][j] = t->data[i][j];
  1170.                 newcflag[i+delta][j] = t->cflag[i][j];
  1171.             }
  1172.         }
  1173.     } else {
  1174.         delta = t->maxy - (rows+scrollback);
  1175.         for (i = 0; i < rows+scrollback; i++) {
  1176.             for (j = 0; j < mincols; j++) {
  1177.                 newdata[i][j] = t->data[i+delta][j];
  1178.                 newcflag[i][j] = t->cflag[i+delta][j];
  1179.             }
  1180.         }
  1181.     }
  1182.  
  1183. /* finally, free the old data and flags */
  1184.     for(i=0; i < t->maxy; i++) {
  1185.         free(t->data[i]); free(t->cflag[i]);
  1186.     }
  1187.     free(t->dirty);
  1188.     free(t->cflag);
  1189.     free(t->data);
  1190.  
  1191.     t->dirty = newdirty;
  1192.     t->cflag = newcflag;
  1193.     t->data = newdata;
  1194.     t->cy = t->cy - SCROLLBACK(t) + scrollback;
  1195.     t->maxx = cols;
  1196.     t->maxy = rows+scrollback;
  1197.     t->miny = scrollback;
  1198.     if (t->cx >= cols) t->cx = 0;
  1199.     if (t->cy >= t->maxy) t->cy = t->maxy-1;
  1200.     if (t->cy < scrollback) t->cy = scrollback;
  1201.     if (t->offy < scrollback * t->cheight)
  1202.         t->offy = scrollback * t->cheight;
  1203.  
  1204.     win_flourishes = 0;
  1205.     if (w->wi_handle >= 0) {
  1206.         wind_close(w->wi_handle);
  1207.         wind_delete(w->wi_handle);
  1208.         reopen = 1;
  1209.     }
  1210.     w->wi_handle = -1;
  1211.  
  1212.     width = t->maxx * t->cmaxwidth;
  1213.     height = rows * t->cheight;
  1214.  
  1215.     wind_calc(WC_BORDER, w->wi_kind, w->wi_fullx, w->wi_fully, width,
  1216.         height, &dummy, &dummy, &w->wi_fullw, &w->wi_fullh);
  1217.     if (w->wi_fullw > wdesk) w->wi_fullw = wdesk;
  1218.     if (w->wi_fullh > hdesk) w->wi_fullh = hdesk;
  1219.  
  1220.     if (w->wi_fullx + w->wi_fullw > xdesk + wdesk)
  1221.         w->wi_fullx = xdesk + (wdesk - w->wi_fullw)/2;
  1222.     if (w->wi_fully + w->wi_fullh > ydesk + hdesk)
  1223.         w->wi_fully = ydesk + (hdesk - w->wi_fullh)/2;
  1224.  
  1225.     wind_calc(WC_WORK, w->wi_kind, w->wi_fullx, w->wi_fully, w->wi_fullw, w->wi_fullh,
  1226.         &dummy, &dummy, &width, &height);
  1227.  
  1228.     if (w->wi_w > width) w->wi_w = width;
  1229.     if (w->wi_h > height) w->wi_h = height;
  1230.  
  1231.     if (reopen)
  1232.         open_window(w);
  1233.     win_flourishes = oldflourishes;
  1234. }
  1235.  
  1236. /* set the "cwidths" array for the given window correctly;
  1237.  * this function may be called ONLY when the font & height are already
  1238.  * set correctly, and only after t->cmaxwidth is set
  1239.  */
  1240.  
  1241. static void
  1242. set_cwidths(t)
  1243.     TEXTWIN *t;
  1244. {
  1245.     int i, status, dummy, wide;
  1246.     int widths[256];
  1247.     int monospaced = 1;
  1248.     int dfltwide;
  1249.  
  1250.     if (t->cwidths) {
  1251.         free(t->cwidths);
  1252.         t->cwidths = 0;
  1253.     }
  1254.     vqt_width(vdi_handle, DEFAULT_CHAR, &dfltwide, &dummy, &dummy);
  1255.  
  1256.     for (i = 0; i < 255; i++) {
  1257.         status = vqt_width(vdi_handle, i, &wide, &dummy, &dummy);
  1258.         if (status == -1) wide = dfltwide;
  1259.         if (wide != t->cmaxwidth)
  1260.             monospaced = 0;
  1261.         widths[i] = wide;
  1262.     }
  1263.     if (!monospaced) {
  1264.         t->cwidths = malloc(256 * sizeof(short));
  1265.         if (!t->cwidths) return;
  1266.         for (i = 0; i < 255; i++)
  1267.             t->cwidths[i] = widths[i];
  1268.     }
  1269. }
  1270.